import xml.etree.ElementTree as ET
import os


def convert(size, box):
    x_center = (box[0] + box[1]) / 2.0
    y_center = (box[2] + box[3]) / 2.0
    x = x_center / size[0]
    y = y_center / size[1]
    w = (box[1] - box[0]) / size[0]
    h = (box[3] - box[2]) / size[1]
    return (x, y, w, h)


def convert_annotation(xml_files_path, save_txt_files_path, classes):
    # 遍历文件夹及其子文件夹
    for root, _, files in os.walk(xml_files_path):
        # 获取相对于根目录的相对路径
        relative_path = os.path.relpath(root, xml_files_path)

        # 在目标路径中创建相应的子文件夹
        target_txt_folder = os.path.join(save_txt_files_path, relative_path)
        os.makedirs(target_txt_folder, exist_ok=True)

        for xml_name in files:
            if not xml_name.endswith('.xml'):
                continue  # 跳过非 XML 文件

            # 输出信息
            print(f"Processing {xml_name}...")

            # 完整 XML 文件路径
            xml_file = os.path.join(root, xml_name)
            # 对应的输出 txt 文件路径
            out_txt_path = os.path.join(target_txt_folder, xml_name.split('.')[0] + '.txt')

            # 打开输出文件
            with open(out_txt_path, 'w') as out_txt_f:
                tree = ET.parse(xml_file)
                root_element = tree.getroot()
                size = root_element.find('size')
                w = int(size.find('width').text)
                h = int(size.find('height').text)

                for obj in root_element.iter('object'):
                    if obj.find('difficult'):
                        difficult = int(obj.find('difficult').text)
                    else:
                        difficult = 0
                    cls = obj.find('name').text
                    if cls not in classes or difficult == 1:
                        continue  # 跳过不在类别列表中的类别或困难物体
                    cls_id = classes.index(cls)
                    xmlbox = obj.find('bndbox')
                    b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text),
                         float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
                    bb = convert((w, h), b)
                    out_txt_f.write(f"{cls_id} " + " ".join([str(a) for a in bb]) + "\n")
                print(f"Saved {out_txt_path}")


if __name__ == "__main__":
    # 改成自己的类别
    classes = ['asiaticblack bear', 'hare', 'hog badger', 'macaques', 'masked civet', 'muntjac',
               'silver pheasant', 'squirrel', 'tragopan']

    # XML 文件所在路径（VOC 标签文件夹）
    xml_files_path = r'D:\file\postgrad\experiment\silver_spare_dataset\merge_label_xml_resize1'

    # YOLO 格式 txt 文件保存路径
    save_txt_files_path = r'D:\file\postgrad\experiment\silver_spare_dataset\merge_label_txt_resize1'

    # 执行转换
    convert_annotation(xml_files_path, save_txt_files_path, classes)

